#include "LPC17xx.h"
#include "lpc17xx_pinsel.h"
#include "lpc17xx_gpio.h"
#include "lpc17xx_i2c.h"
#include "lpc17xx_ssp.h"
#include "lpc17xx_timer.h"
#include "lpc17xx_uart.h"
#include "stdio.h"
#include "string.h"
#include "acc.h"
#include "light.h"
#include "oled.h"
#include "rgb.h"
#include "joystick.h"
#include "Extra_functions.h"

#define LIGHT 0
#define DARK 1
#define ALERT 2

#define Detect 0
#define Co_op 1
#define Settings 2

extern int asm_variance(int x, int mean, int reset, int* max);
extern void OLED_print(unsigned int sample_light, uint8_t z, uint8_t sample_mean, uint8_t sample_variance, uint8_t max);
extern void Alarm(uint8_t ch, uint32_t time);

int shock = 0;
int mode = 0;
int reset = 1;
uint32_t msTicks;
int8_t x = 0;
int8_t y = 0;
int8_t z = 0;

char letter[] = {'a','b','c','d','e','f','g','A','B','C','D','E','F','G'};
int i=0;
char str[3];

/*Initial Settings*/

uint8_t data = 0;
uint32_t len = 0;
uint8_t line[64];

int sample_mean = 79;
int max = 0;
int sample_light, max_lux, ref_lux;
int sample_variance, max_var, ref_var;
int state = LIGHT;

uint8_t note = 'G';
uint32_t time = 250;
char str1[15];

void SysTick_Handler(void)
{
	if (state != ALERT)
	{
		sample_light = light_read();
		switch (mode)
		{
		case Detect:
			state = LIGHT;
			sample_light = light_read();
			if (sample_light < 100)
			{
				state = DARK;
				acc_read(&x, &y, &z);
				sample_variance = asm_variance (z, sample_mean, reset, &max);
				if (reset == 1)
					reset = 0;
				sample_mean = z;
				if (sample_variance > 100)
				{
					state = ALERT;
				}
			}
			break;

		case Co_op:

			acc_read(&x,&y,&z);
			sample_mean = z;
			sample_variance = asm_variance(z,sample_mean, reset, &max);

			if (reset == 1)
				reset = 0;
			if (sample_light > max_lux)
				max_lux = sample_light;
			if (sample_variance > max_var)
				max_var = sample_variance;

			break;
		}
	}
}
static void init_ssp(void)
{
	// for the OLED
	SSP_CFG_Type SSP_ConfigStruct;
	PINSEL_CFG_Type PinCfg;

	/*
	* Initialize SPI pin connect
	* P0.7 - SCK;
	* P0.8 - MISO
	* P0.9 - MOSI
	* P2.2 - SSEL - used as GPIO
	*/

	PinCfg.Funcnum = 2;
	PinCfg.OpenDrain = 0;
	PinCfg.Pinmode = 0;
	PinCfg.Portnum = 0;
	PinCfg.Pinnum = 7;
	PINSEL_ConfigPin(&PinCfg);

	PinCfg.Pinnum = 8;
	PINSEL_ConfigPin(&PinCfg);

	PinCfg.Pinnum = 9;
	PINSEL_ConfigPin(&PinCfg);

	PinCfg.Funcnum = 0;
	PinCfg.Portnum = 2;
	PinCfg.Pinnum = 2;
	PINSEL_ConfigPin(&PinCfg);

	SSP_ConfigStructInit(&SSP_ConfigStruct);

	// Initialize SSP peripheral with parameter given in structure above
	SSP_Init(LPC_SSP1, &SSP_ConfigStruct);

	// Enable SSP peripheral
	SSP_Cmd(LPC_SSP1, ENABLE);
}

static void init_i2c(void)
{ // For various sensors
	PINSEL_CFG_Type PinCfg;

	/*---Initialize I2C2 pin---> */
	PinCfg.Funcnum = 2;
	PinCfg.Pinnum = 10;
	PinCfg.Portnum = 0;
	PINSEL_ConfigPin(&PinCfg);
	PinCfg.Pinnum = 11;
	PINSEL_ConfigPin(&PinCfg);

	/*--- Initialize I2C peripheral---> */
	I2C_Init(LPC_I2C2, 100000);

	/*--- Enable I2C1 operation---> */
	I2C_Cmd(LPC_I2C2, ENABLE);
}

static void init_GPIO(void)
{
	/*---Initialize SW4----> */
	PINSEL_CFG_Type PinCfg;
	PinCfg.Funcnum = 0;
	PinCfg.OpenDrain = 0;
	PinCfg.Pinmode = 0;
	PinCfg.Portnum = 1;
	PinCfg.Pinnum = 31;
	PINSEL_ConfigPin(&PinCfg);
	GPIO_SetDir(1, 1<<31, 0);

	/*---Initialize SW3---> */
	PinCfg.Portnum = 0;
	PinCfg.Pinnum = 4;
	PINSEL_ConfigPin(&PinCfg);
	GPIO_SetDir(0, 1<<4, 0);

	/* ---- Speaker ------> */
	GPIO_SetDir(2, 1<<0, 1);
	GPIO_SetDir(2, 1<<1, 1);

	GPIO_SetDir(0, 1<<27, 1);
	GPIO_SetDir(0, 1<<28, 1);
	GPIO_SetDir(2, 1<<13, 1);
	GPIO_SetDir(0, 1<<26, 1);

	GPIO_ClearValue(0, 1<<27); //LM4811-clk
	GPIO_ClearValue(0, 1<<28); //LM4811-up/dn
	GPIO_ClearValue(2, 1<<13); //LM4811-shutdn

	/* ---- RGB ---> */
	GPIO_SetDir( 2, 0, 1 );
}

/* ---- UART ---> */
void pinsel_uart3(void){
	PINSEL_CFG_Type PinCfg;
	PinCfg.Funcnum = 2;
	PinCfg.Pinnum = 0;
	PinCfg.Portnum = 0;
	PINSEL_ConfigPin(&PinCfg);
	PinCfg.Pinnum = 1;
	PINSEL_ConfigPin(&PinCfg);
}

void init_uart(void){
	UART_CFG_Type uartCfg;
	uartCfg.Baud_rate = 115200;
	uartCfg.Databits = UART_DATABIT_8;
	uartCfg.Parity = UART_PARITY_NONE;
	uartCfg.Stopbits = UART_STOPBIT_1;
	pinsel_uart3();
	UART_Init(LPC_UART3, &uartCfg);
	UART_TxCmd(LPC_UART3, ENABLE);
}

/* ----Interrupts---> */

/*---SW3 Interrupt (for clearing alarm)-->*/
void EINT3_IRQHandler()
{
	if ((LPC_GPIOINT->IO0IntStatF>>4)& 0x1)
	{
		if (state == ALERT)
		{
		reset = 1;
		acc_read(&x,&y,&sample_mean);
		state = LIGHT;
		}
		LPC_GPIOINT->IO0IntClr = 1<<4;
	}
}

int isMax(int ref, int *max)
{
	int i;
	for (i=0; i<4; i++)
	{
		if (ref < max[i])
			return 0;
	}
	return 1;
}

// UART interrupt
void UART3_IRQHandler(void)
{
	uint8_t data = 0;
	int B_vars[4] = {0};
	char str[16];

	if (LPC_UART3->IIR & UART_IIR_INTID_RDA)
	{
		UART_Receive(LPC_UART3, &data, 1, NONE_BLOCKING);
		if (data != '\r')
		{
			len++;
			line[len-1] = data;
		}
		else
		{
			line[len] = 0;
			len = 0;

			if (strcmp((const char *)line,"IDQ") == 0)
				UART_SendString(LPC_UART3, (uint8_t *)"IDR 62 EE2024\r\n");
			else if (strcmp((const char *)line,"REQ") == 0) {
				ref_var = max_var;
				sprintf(str,"RER %d %u\r\n",max_var,max_lux);
				max_var = max_lux = 0;
				UART_SendString(LPC_UART3, (uint8_t *)str);
			}
			else if (strncmp ((const char *)line,"B ",2) == 0) {

				if (sscanf((char *)line,"B %d %d %d %d", &B_vars[0], &B_vars[1], &B_vars[2], &B_vars[3]) == 4) {
					if (isMax (ref_var,B_vars) == 1) {
						UART_SendString(LPC_UART3, (uint8_t *)"MEE\r\n");
						state = ALERT;
					} else {
						UART_SendString(LPC_UART3, (uint8_t *)"NME\r\n");
					}
				}
				else
					UART_SendString(LPC_UART3, (uint8_t *)"Error: Invalid Input\r\n");
			}
			else if (strcmp((const char *)line,"SAQ") == 0) {
				state = DARK;
				UART_SendString(LPC_UART3, (uint8_t *)"SAA\r\n");
			}
			else if (strcmp((const char *)line,"END") == 0) {
				UART_SendString(LPC_UART3, (uint8_t *)"ENA\r\n");
			}
			else
				UART_SendString(LPC_UART3, (uint8_t *)"Error: Invalid Input\r\n");
		}
	}
}

int main()
{
	init_i2c();
	init_ssp();
	init_GPIO();
	init_uart();
	joystick_init();
	acc_init();
	oled_init();
	light_enable();

	uint8_t status;

	SysTick_Config(SystemCoreClock/25); //40ms

	LPC_GPIOINT->IO0IntEnF |= 1<<4;
	NVIC_EnableIRQ(EINT3_IRQn);
	NVIC_EnableIRQ(UART3_IRQn);

	oled_clearScreen(OLED_COLOR_BLACK);
	oled_putString(0,0,(unsigned char*) "Detect Mode", OLED_COLOR_WHITE, OLED_COLOR_BLACK);

	acc_read(&x,&y,&z);
	sample_mean = z;

	OLED_print(sample_light, z, sample_mean, sample_variance, max);
	UART_SendString(LPC_UART3, (uint8_t *)"Ready to execute\r\n"); // Check if UART connection is ON

	if (SysTick_Config(SystemCoreClock / 25)) {
		while (1)
			;
	}
	while(1) {
		if (mode !=Settings)
		{
			OLED_print(sample_light, z, sample_mean, sample_variance, max);

				while (state == ALERT)
				{
					Alarm(letter[i], time);
				}
		}
// Configuration for settings

		if (mode == Settings)
			{
			status = joystick_read();
			if ((status & JOYSTICK_RIGHT) != 0)
				{
					i++;
			    }
			if ((status & JOYSTICK_LEFT) != 0)
				{
					if (i==0)
						i = 14;
					else
						i--;
				}

			i = i%15;
			sprintf(str,"Tone: %c  ", letter[i]);
			oled_putString(0,10,(uint8_t*) str, OLED_COLOR_BLACK, OLED_COLOR_WHITE);
			Timer0_Wait(200);
			}
// Switch modes by pressing SW4

		if (((GPIO_ReadValue(1) >> 31) & 0x01) == 0) {
			if (mode == Detect) {
				mode = Co_op;
				oled_clearScreen(OLED_COLOR_BLACK);
				oled_putString(0,0,(unsigned char*) "Co-op  Mode", OLED_COLOR_WHITE, OLED_COLOR_BLACK);
				state = 1;
				time = 500;
				reset = 1;
				LPC_UART3->IER = UART_IER_RBRINT_EN; // Enable UART interrupt
			}
			else if (mode == Co_op) {
				mode = Settings;
				oled_clearScreen(OLED_COLOR_BLACK);
				oled_putString(0,0,(unsigned char*) "Settings", OLED_COLOR_WHITE, OLED_COLOR_BLACK);
				time = 250;
				max_lux = 0;
				max_var = 0;

				LPC_UART3->IER = 0;  // Disable UART interrupt

			}
			else {
				oled_clearScreen(OLED_COLOR_BLACK);
				oled_putString(0,0,(unsigned char*) "Detect Mode", OLED_COLOR_WHITE, OLED_COLOR_BLACK);
				mode = Detect;
			}
			Timer0_Wait(150);
		}
	}
}

